package com.tbvtc.agriculturalcreditchainserver2025.service.impl;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tbvtc.agriculturalcreditchainserver2025.constant.RedisConstant;
import com.tbvtc.agriculturalcreditchainserver2025.dto.ChatMessage.GetAllChatValueDto;
import com.tbvtc.agriculturalcreditchainserver2025.entity.ChatMessage;
import com.tbvtc.agriculturalcreditchainserver2025.entity.Crop;
import com.tbvtc.agriculturalcreditchainserver2025.entity.User;
import com.tbvtc.agriculturalcreditchainserver2025.entity.websocket.RedisChatSnapshot;
import com.tbvtc.agriculturalcreditchainserver2025.entity.websocket.WebSocketMessage;
import com.tbvtc.agriculturalcreditchainserver2025.enumeration.ChatType;
import com.tbvtc.agriculturalcreditchainserver2025.enumeration.MessageType;
import com.tbvtc.agriculturalcreditchainserver2025.login.LoginUserHolder;
import com.tbvtc.agriculturalcreditchainserver2025.mapper.ChatMessageMapper;
import com.tbvtc.agriculturalcreditchainserver2025.service.IChatMessageService;
import com.tbvtc.agriculturalcreditchainserver2025.service.IUserService;
import com.tbvtc.agriculturalcreditchainserver2025.utils.RUtils;
import com.tbvtc.agriculturalcreditchainserver2025.utils.Result;
import com.tbvtc.agriculturalcreditchainserver2025.utils.SpringContextUtil;
import com.tbvtc.agriculturalcreditchainserver2025.utils.voice.VoiceFileUtil;
import com.tbvtc.agriculturalcreditchainserver2025.vo.PageVo;
import com.tbvtc.agriculturalcreditchainserver2025.vo.chatMessage.GetAllChatValueVo;
import com.tbvtc.agriculturalcreditchainserver2025.ws.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * <p>
 * 聊天消息主表（存储单聊/群聊/广播消息） 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-11-03
 */
@Service
@Slf4j
public class ChatMessageServiceImpl extends ServiceImpl<ChatMessageMapper, ChatMessage> implements IChatMessageService {
    private static final Snowflake snowflake = new Snowflake(1L, 1L);
    @Resource(name = "TredisTemplate")
    private RedisTemplate<String, RedisChatSnapshot> redisTemplate;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    private IUserService userService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long singleSend(WebSocketMessage webSocketMessage) throws IOException {
        log.info("开始存入数据库{}", webSocketMessage.toString());
        ChatMessage chatMessage = new ChatMessage();
        ChatMessage notContentChatMessage = new ChatMessage();
        // workerId, datacenterId
        long id = snowflake.nextId();
        //首先将基础信息存入对象
        chatMessage.setId(id);
        chatMessage.setSenderId(webSocketMessage.getSenderId());
        chatMessage.setSendTime(LocalDateTime.now());
        chatMessage.setDeleteStatus(0);
        chatMessage.setReadStatus(0);
        chatMessage.setExtJson("");
        //1单聊2群聊,3广播
        // 简化接收类型设置（仅保留单聊和广播）
        if (webSocketMessage.getChatType() == ChatType.SINGLE_SEND) {
            //未读消息，存储在redis中，以senderID和receiverID为键，消息ID为值
            chatMessage.setReceiverType(1);
            stringRedisTemplate.opsForValue().increment(RedisConstant.CHAT_MESSAGE_COUNT_KEY +
                            webSocketMessage.getReceiverId().get(0) +
                            ":" + webSocketMessage.getSenderId()
                    , 1);
        } else if (webSocketMessage.getChatType() == ChatType.BROADCAST_SEND) {
            chatMessage.setReceiverType(3);
        }
        if (webSocketMessage.getChatType() == ChatType.SINGLE_SEND) {
            chatMessage.setReceiverId(webSocketMessage.getReceiverId().get(0));
        } else if (webSocketMessage.getChatType() == ChatType.BROADCAST_SEND) {
            chatMessage.setReceiverId("BROADCAST"); // 广播固定接收者标识，与表设计一致
        }
        chatMessage.setMessageType(webSocketMessage.getMessageType().getType());
        //拷贝消息内容
        BeanUtil.copyProperties(webSocketMessage, notContentChatMessage);
        if (webSocketMessage.getMessageType() == MessageType.IMAGE) {
            //图片：文本为图片的描述，文件路径为图片的保存路径
            if (webSocketMessage.getContent() == null || !webSocketMessage.getFilePath().isEmpty()) {
                chatMessage.setFilePath(webSocketMessage.getFilePath().get(0));
                notContentChatMessage.setContent("图片");
            } else {
                chatMessage.setContent(webSocketMessage.getContent().get(0));
            }

        } else if (webSocketMessage.getMessageType() == MessageType.AUDIO) {
            chatMessage.setFilePath(webSocketMessage.getFilePath().get(0));
            //语音：文本为空，文件路径为保存的音频文件路径
            chatMessage.setVoiceLength(webSocketMessage.getVoiceLength());
            notContentChatMessage.setContent("语音");
        } else {
            //纯文本储存文本
            chatMessage.setContent(webSocketMessage.getContent().get(0));
        }
        //最新消息查询，有文本存文本，无文本存音频或者图片
        if (webSocketMessage.getMessageType() == MessageType.TEXT) {
            saveTestToRedis(id, chatMessage);
        } else {
            saveTestToRedis(id, notContentChatMessage);
        }
        //不管有无消息内容都存入数据库
        save(chatMessage);
        log.info("存入数据库成功{}", chatMessage);
        return chatMessage.getId();
    }


    @Override
    public Result getAllChatValue(GetAllChatValueDto getAllChatValueDto) {
        Page<ChatMessage> page = new Page<>(getAllChatValueDto.getPageNum(), getAllChatValueDto.getPageSize());
        // 构建查询条件：双向匹配 + 按发送时间排序
        String senderId = getAllChatValueDto.getSenderId();
        Long receiverId = getAllChatValueDto.getReceiverId();
        Page<ChatMessage> pageValue = page(page, new QueryWrapper<ChatMessage>()
                // 条件1：A发给B  或者  条件2：B发给A
                .and(wrapper -> wrapper
                        .eq("sender_id", senderId).eq("receiver_id", receiverId)
                        .or()
                        .eq("sender_id", receiverId).eq("receiver_id", senderId)
                )
                // 按发送时间升序（ oldest → newest ），保证消息按时间线排列
                .orderByAsc("send_time")
        );
        PageVo<GetAllChatValueVo> objectPageVo = new PageVo<>();
        List<ChatMessage> records = pageValue.getRecords();
        User receiver = userService.getById(receiverId);
        User sender = userService.getById(senderId);
        List<ChatMessage> noReadList = records.stream()
                .filter(vo -> vo.getReadStatus() == 0)
                .map(vo -> vo.setReadStatus(1))
                .collect(Collectors.toList());
        if (!noReadList.isEmpty()){
            log.info("开始更新已读消息");
            updateBatchById(noReadList);
            log.info("开始推送");
            WebSocketMessage webSocketMessage = WebSocketMessage.builder()
                    .chatType(ChatType.SINGLE_SEND)
                    .messageType(MessageType.NOTICE)
                    .content(new ArrayList<>(Collections.singletonList("已读")))
                    .senderId(senderId)
                    .receiverId(new ArrayList<>(Collections.singletonList(receiverId.toString())))
                    .groupId("")
                    .metadata(new ArrayList<>())
                    .filePath(new ArrayList<>())
                    .voiceLength(0)
                    .build();
            try {
                WebSocketServer.sendToUserStatic(JSON.toJSONString(webSocketMessage), receiverId.toString());
                log.info("推送已读消息成功");
                log.info("开始推送已读消息给{},内容为{}", receiverId,webSocketMessage.toString());
            } catch (IOException e) {
                log.error("推送已读消息失败");
            }
        }


        List<GetAllChatValueVo> getAllChatValueVos = BeanUtil.copyToList(records, GetAllChatValueVo.class);
        getAllChatValueVos.forEach(vo -> {
            vo.setReadStatus(1);
            if (vo.getReceiverId().equals(String.valueOf(receiverId))) {
                vo.setSenderImage(sender.getUserImage());
                vo.setReceiverImage(receiver.getUserImage());
            } else {
                vo.setSenderImage(receiver.getUserImage());
                vo.setReceiverImage(sender.getUserImage());
            }

        });
        objectPageVo.setTotal(pageValue.getTotal());
        objectPageVo.setRecords(getAllChatValueVos);
        return RUtils.success(objectPageVo);
    }

    @Override
    public String getCount(String receiverId, Long chatId) {
        ChatMessage chatMessage = getById(chatId);
        GetAllChatValueVo getAllChatValueVo = BeanUtil.copyProperties(chatMessage, GetAllChatValueVo.class);
        getAllChatValueVo.setSenderImage(userService.getById(chatMessage.getSenderId()).getUserImage());
        getAllChatValueVo.setReceiverImage(userService.getById(receiverId).getUserImage());
        return JSON.toJSONString(getAllChatValueVo);
    }


    private void saveTestToRedis(Long id, ChatMessage chatMessage) {
        User user = userService.getById(chatMessage.getSenderId());
        RedisChatSnapshot redisChatSnapshot = new RedisChatSnapshot();
        // 省略赋值逻辑...
        redisChatSnapshot.setMsgId(id);
        redisChatSnapshot.setSenderId(user.getId());
        redisChatSnapshot.setContent(chatMessage.getContent());
        redisChatSnapshot.setSenderName(user.getUsername());
        redisChatSnapshot.setSenderAvatar(user.getUserImage());
        redisChatSnapshot.setSendTime(chatMessage.getSendTime());
        // 构建 Redis 哈希键（键格式不变，值类型改为哈希）
        String redisKey = RedisConstant.CHAT_SNAPSHOT_KEY_PREFIX + chatMessage.getReceiverId();
        // 以 SenderId 作为哈希的 field（自动覆盖相同 field 的旧值）
        redisTemplate.opsForHash().put(redisKey, user.getId().toString(), redisChatSnapshot);
        //如果自己向他人发送消息，也需要向redis中存储最新消息用于显示
        String userId = LoginUserHolder.getLoginUser().getUserId().toString();
//        if (chatMessage.getSenderId().equals(userId)) {
//            String Key = RedisConstant.CHAT_SNAPSHOT_KEY_PREFIX + userId;
//            //当自己是发送者的时候，为了拿到最新数据，对面的接收者id就成了发送者id
//            redisChatSnapshot.setSenderId(Integer.valueOf(chatMessage.getReceiverId()));
//            redisTemplate.opsForHash().put(Key, chatMessage.getReceiverId(), redisChatSnapshot);
//        }
    }
}
